
package org.amos.upms.modules.system.controller;

import ch.qos.logback.classic.Level;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import io.swagger.v3.oas.annotations.Operation;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import org.amos.core.basic.base.BaseController;
import org.amos.core.basic.constant.SystemConstant;
import org.amos.core.basic.utils.AmosUtils;
import org.amos.core.basic.utils.JsonUtils;
import org.amos.core.basic.utils.crud.BetweenCondition;
import org.amos.core.basic.utils.crud.WrapperBuilder;
import org.amos.core.basic.vo.R;
import org.amos.upms.modules.system.dto.LogDTO;
import org.amos.upms.modules.system.dto.LogStatisticsDTO;
import org.amos.upms.modules.system.entity.Log;
import org.amos.upms.modules.system.service.ILogLoginService;
import org.amos.upms.modules.system.vo.LogHistogramVO;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.text.DecimalFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 日志表 前端控制器
 * </p>
 *
 * @author CodeGenerator
 * @since 2021-01-04
 */
@RestController
@RequiredArgsConstructor
@RequestMapping("/system/log")
public class LogController extends BaseController {

    private final ILogLoginService logService;

    @GetMapping("/list")
    @Operation(description = "日志列表信息")
    public R list(LogDTO dto) {
        IPage<Log> page = logService.page(initPage(dto), buildWrapper(dto));
        return R.ok(page);
    }

    @PostMapping("/update")
    @Operation(description = "更新日志数据")
    public R update(@RequestBody @Validated LogDTO dto) {
        Log dept = AmosUtils.copy(dto, Log.class);
        logService.saveOrUpdate(dept);
        return R.ok();
    }

    @PostMapping("/remove")
    @Operation(description = "删除日志数据")
    public R remove(@RequestBody Set<Long> ids) {
        UpdateWrapper<Log> uw = new UpdateWrapper<>();
        uw.in(AmosUtils.toDbField(Log::getId), ids).set(AmosUtils.toDbField(Log::getIsDeleted), SystemConstant.SYS_DELETE_FLAG_ALREADY);
        logService.update(uw);
        return R.ok();
    }

    @GetMapping("/percentage")
    @Operation(description = "日志各级别占比")
    public R percentage() {
        long total = logService.count();
        QueryWrapper<Log> qw = new QueryWrapper<>();
        qw.select("level,count(*) as count");//查询自定义列
        qw.groupBy(AmosUtils.toDbField(Log::getLevel));
        List<Map<String, Object>> maps = logService.listMaps(qw);

        Map<String, Object> resultMap = new HashMap<>();
        maps.forEach(x -> {
            String level = String.valueOf(x.get("level"));
            Long count = (Long) x.get("count");
            float num = (float) count / total;
            //格式化小数
            DecimalFormat df = new DecimalFormat("0.00");
            String percentage = df.format(num * 100);
            resultMap.put(level, percentage);
        });
        return R.ok(resultMap);
    }

    @GetMapping("/histogram")
    @Operation(description = "柱状图统计数据")
    public R histogram(LogStatisticsDTO dto) {
        // 默认日志查询时间范围
        long defaultTimeCondition = 14;
        long defaultMaxTime = 30;
        String timeConditionStr = dto.getTimeCondition();
        if (StrUtil.isNotBlank(timeConditionStr)) {
            BetweenCondition<String> condition = JsonUtils.jsonToPojo(timeConditionStr, BetweenCondition.class);
            DateTime startTime = DateUtil.parse(condition.getStart());
            DateTime endTime = DateUtil.parse(condition.getEnd());
            long betweenDay = DateUtil.betweenDay(startTime, endTime, true);
            if (betweenDay > defaultMaxTime) {
                return R.error("最多只能查询30天内的日志数据");
            }
        } else {
            DateTime dateTime = DateUtil.offsetDay(new Date(), (int) -(defaultTimeCondition - 1));
            BetweenCondition<String> timeCondition = new BetweenCondition<>();
            timeCondition.setStart(DateUtil.formatDate(dateTime) + " 00:00");
            timeCondition.setEnd(DateUtil.today() + " 23:59");
            dto.setTimeCondition(JsonUtils.objectToJson(timeCondition));
        }

        LogHistogramVO vo = new LogHistogramVO();
        List<String> dateList = new ArrayList<>();
        List<Long> infoList = new ArrayList<>();
        List<Long> errorList = new ArrayList<>();
        QueryWrapper<Log> qw = new WrapperBuilder<>().build(dto);
        qw.select("date_format(create_time, '%Y-%m-%d') as date", "count(create_time) as amount, level")
                .groupBy("date", "level")
                .orderByAsc("date");
        List<Map<String, Object>> maps = logService.listMaps(qw);
        List<LogHistogram> logHistograms = new ArrayList<>();
        maps.forEach(x -> {
            LogHistogram logHistogram = new LogHistogram();
            logHistogram.setLevel(MapUtil.getStr(x, AmosUtils.toDbField(LogHistogram::getLevel)));
            logHistogram.setDate(MapUtil.getStr(x, AmosUtils.toDbField(LogHistogram::getDate)));
            logHistogram.setAmount(MapUtil.getLong(x, AmosUtils.toDbField(LogHistogram::getAmount)));
            logHistograms.add(logHistogram);
        });
        // 按日期分组
        Map<String, List<LogHistogram>> listMap = logHistograms.stream().collect(Collectors.groupingBy(LogHistogram::getDate, LinkedHashMap::new, Collectors.toList()));
        listMap.forEach((k, v) -> {
            dateList.add(k);
            // 按日志级别分组统计
            long infoSum = v.stream().filter(x -> x.getLevel().equals(Level.INFO.levelStr)).mapToLong(LogHistogram::getAmount).sum();
            long errorSum = v.stream().filter(x -> x.getLevel().equals(Level.ERROR.levelStr)).mapToLong(LogHistogram::getAmount).sum();
            infoList.add(infoSum);
            errorList.add(errorSum);

        });
        vo.setDateList(dateList);
        vo.setInfoList(infoList);
        vo.setErrorList(errorList);
        return R.ok(vo);
    }

    @Data
    public static class LogHistogram {
        private String date;
        private String level;
        private Long amount;
    }
}
